package cn.elegent.lock.strategy.redis;

import cn.elegent.lock.ELegentLock;
import cn.elegent.lock.config.RedisRedLockConfig;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import javax.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;

/**
 * redis分布式锁(红锁)实现类
 */
@ConditionalOnProperty(prefix = "elegent.lock",name = "type",havingValue = "redlock")
@Slf4j
public class RedisRedLock implements ELegentLock {

    @Autowired
    private RedisRedLockConfig redisLockConfig;

    //客户端
    private RedissonClient [] redissonClients;


    @PostConstruct
    public void init(){
        log.info( "address:   " +redisLockConfig.getAddress().toString() );
        if(redisLockConfig.getAddress()==null){
            log.info("redis红锁地址未配置");
            return ;
        }
        if(redisLockConfig.getAddress().length<3){
            log.info("redis红锁地址数量不能小于3"+redisLockConfig.getAddress().length);
            return ;
        }
        //初始化
        redissonClients=new RedissonClient[ redisLockConfig.getAddress().length  ];

        for(int i=0;i<redisLockConfig.getAddress().length;i++){
            Config config = new Config();
            config.useSingleServer().setAddress( "redis://"+redisLockConfig.getAddress()[i] );
            redissonClients[i] = Redisson.create(config);
        }

    }


    /**
     * 加锁
     *
     * @param lockName
     */
    public boolean lock(String lockName) {
        //红锁
        RedissonRedLock redLock=getRedissonRedLock(lockName);
        if(redisLockConfig.isRenewal()){  //如果续期
            redLock.lock(-1,TimeUnit.SECONDS);  //-1 启动看门狗
        }else{
            redLock.lock(redisLockConfig.getTtl(),TimeUnit.SECONDS);
        }
        log.info("redis加锁成功，锁名称：{}",lockName);
        return true;
    }


    private RedissonRedLock getRedissonRedLock(String lockName){
        RLock lock0 = redissonClients[0].getLock(lockName);
        RLock lock1 = redissonClients[1].getLock(lockName);
        RLock lock2 = redissonClients[2].getLock(lockName);
        //红锁
        if(redissonClients.length<5){  //不够5个，就取前3个
            log.info("redis红锁成功3个节点");
            return new RedissonRedLock(lock0,lock1,lock2);
        }else{  //5个
            RLock lock3 = redissonClients[3].getLock(lockName);
            RLock lock4 = redissonClients[4].getLock(lockName);
            log.info("redis红锁成功5个节点");
            return new RedissonRedLock(lock0, lock1, lock2,lock3,lock4);
        }
    }

    /**
     * 尝试获取锁
     *
     * @param lockName
     * @return
     */
    public boolean tryLock(String lockName) {
        //红锁
        RedissonRedLock redLock=getRedissonRedLock(lockName);
        try {
            boolean isLock;
            if(redisLockConfig.isRenewal()) {  //如果续期
                isLock= redLock.tryLock(redisLockConfig.getWait(),-1,TimeUnit.SECONDS);//-1 启动看门狗
            }else{
                isLock= redLock.tryLock(redisLockConfig.getWait(),redisLockConfig.getTtl(),TimeUnit.SECONDS);
            }
            if(isLock){
                log.info("redis加红锁成功，锁名称：{}",lockName);
            }else{
                log.info("redis加红锁失败，锁名称：{}",lockName);
            }
            return isLock;
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.info("redis加红锁出错，锁名称：{}",lockName);
            return false;
        }
    }


    /**
     * 释放锁
     *
     * @param lockName
     */
    public boolean unLock(String lockName) {
        try {
            RedissonRedLock redLock=getRedissonRedLock(lockName);
            redLock.unlock();
            log.info("redis释放锁成功，锁名称：{}",lockName);
            return true;
        }catch (Exception e){
            e.printStackTrace();
            log.info("redis释放锁出错，锁名称：{}",lockName);
            return false;
        }
    }

    /**
     * 是否存在锁
     *
     * @param lockName
     * @return
     */
    public boolean isLocked(String lockName) {
        return false;
    }
}
